using Acme.BookStore.Purchase.Customergoods;
using Acme.BookStore.PurchaseDto.CustomergoodsDto;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace Acme.BookStore.Purchase.Customergoods
{
    public class CustomergoodsService : CrudAppService<
        CustomergoodsModel,
        CustomergoodsDto,
        Guid,
        PagedAndSortedResultRequestDto,
        CreateUpdateCustomergoodsDto>,
        ICustomergoodsService
    {
        private readonly IRepository<IdentityUser, Guid> _userRepository;

        public CustomergoodsService(
            IRepository<CustomergoodsModel, Guid> repository,
            IRepository<IdentityUser, Guid> userRepository)
            : base(repository)
        {
            _userRepository = userRepository;
        }

        public Task<PagedResultDto<CustomergoodsDto>> GetListAsync(PagedAndSortedResultRequestDto input)
        {
            var queryable = await Repository.GetQueryableAsync();
            var userQueryable = await _userRepository.GetQueryableAsync();

            var query = from customergoods in queryable
                       join user in userQueryable on customergoods.CreatorId equals user.Id into userJoin
                       from user in userJoin.DefaultIfEmpty()
                       select new CustomergoodsDto
                       {
                           Id = customergoods.Id,
                           PurchaseOrderNo = customergoods.PurchaseOrderNo,
                           SupplierCode = customergoods.SupplierCode,
                           CarNo = customergoods.CarNo,
                           DriverName = customergoods.DriverName,
                           DriverPhone = customergoods.DriverPhone,
                           Status = customergoods.Status,
                           Shipper = customergoods.Shipper,
                           EstimatedArrivalTime = customergoods.EstimatedArrivalTime,
                           CustomerOrderNo = customergoods.CustomerOrderNo,
                           TransportNo = customergoods.TransportNo,
                           TransportCompany = customergoods.TransportCompany,
                           Supplier = customergoods.Supplier,
                           ReservedWarehouseArea = customergoods.ReservedWarehouseArea,
                           Warehouse = customergoods.Warehouse,
                           OrderType = customergoods.OrderType,
                           Remarks = customergoods.Remarks,
                           AttachmentPath = customergoods.AttachmentPath,
                           CreatorId = customergoods.CreatorId,
                           CreationTime = customergoods.CreationTime,
                           LastModifierId = customergoods.LastModifierId,
                           LastModificationTime = customergoods.LastModificationTime,
                           CreatorName = user != null ? user.UserName : string.Empty
                       };

            var totalCount = await AsyncExecuter.CountAsync(query);

            var items = await AsyncExecuter.ToListAsync(
                query.OrderBy(input.Sorting ?? nameof(CustomergoodsModel.Id)).PageBy(input)
            );

            return new PagedResultDto<CustomergoodsDto>(totalCount, items);
        }

        public async Task<ListResultDto<ICustomergoodsService.OrderTypeModelDto>> GetOrderTypeModelAsync()
        {
            var list = Enum.GetValues(typeof(OrderTypeModel))
                .Cast<OrderTypeModel>()
                .Select(x => new ICustomergoodsService.OrderTypeModelDto
                {
                    Id = (int)x,
                    Name = x.ToString()
                }).ToList();

            return new ListResultDto<ICustomergoodsService.OrderTypeModelDto>(list);
        }

        public async Task<ListResultDto<ICustomergoodsService.ReservedWarehouseAreaModelDto>> GetReservedWarehouseAreaModelAsync()
        {
            var list = Enum.GetValues(typeof(ReservedWarehouseAreaModel))
                .Cast<ReservedWarehouseAreaModel>()
                .Select(x => new ICustomergoodsService.ReservedWarehouseAreaModelDto
                {
                    Id = (int)x,
                    Name = x.ToString()
                }).ToList();

            return new ListResultDto<ICustomergoodsService.ReservedWarehouseAreaModelDto>(list);
        }

        public async Task<ListResultDto<ICustomergoodsService.WarehouseModelDto>> GetWarehouseModelAsync()
        {
            var list = Enum.GetValues(typeof(WarehouseModel))
                .Cast<WarehouseModel>()
                .Select(x => new ICustomergoodsService.WarehouseModelDto
                {
                    Id = (int)x,
                    Name = x.ToString()
                }).ToList();

            return new ListResultDto<ICustomergoodsService.WarehouseModelDto>(list);
        }

        public async Task<PagedResultDto<CustomergoodsDto>> GetListByConditionsAsync(CustomgoodsQueryDto input)
        {
            var queryable = await Repository.GetQueryableAsync();
            var userQueryable = await _userRepository.GetQueryableAsync();

            var query = from customergoods in queryable
                       join user in userQueryable on customergoods.CreatorId equals user.Id into userJoin
                       from user in userJoin.DefaultIfEmpty()
                       where (string.IsNullOrWhiteSpace(input.PurchaseOrderNo) || customergoods.PurchaseOrderNo.Contains(input.PurchaseOrderNo))
                             && (string.IsNullOrWhiteSpace(input.CustomerOrderNo) || customergoods.CustomerOrderNo.Contains(input.CustomerOrderNo))
                             && (string.IsNullOrWhiteSpace(input.CarNo) || customergoods.CarNo.Contains(input.CarNo))
                             && (string.IsNullOrWhiteSpace(input.DriverName) || customergoods.DriverName.Contains(input.DriverName))
                             && (string.IsNullOrWhiteSpace(input.DriverPhone) || customergoods.DriverPhone.Contains(input.DriverPhone))
                             && (string.IsNullOrWhiteSpace(input.Status) || customergoods.Status.Contains(input.Status))
                             && (!input.ExpectedArrivalDateFrom.HasValue || customergoods.EstimatedArrivalTime >= input.ExpectedArrivalDateFrom)
                             && (!input.ExpectedArrivalDateTo.HasValue || customergoods.EstimatedArrivalTime <= input.ExpectedArrivalDateTo)
                       select new CustomergoodsDto
                       {
                           Id = customergoods.Id,
                           PurchaseOrderNo = customergoods.PurchaseOrderNo,
                           SupplierCode = customergoods.SupplierCode,
                           CarNo = customergoods.CarNo,
                           DriverName = customergoods.DriverName,
                           DriverPhone = customergoods.DriverPhone,
                           Status = customergoods.Status,
                           Shipper = customergoods.Shipper,
                           EstimatedArrivalTime = customergoods.EstimatedArrivalTime,
                           CustomerOrderNo = customergoods.CustomerOrderNo,
                           TransportNo = customergoods.TransportNo,
                           TransportCompany = customergoods.TransportCompany,
                           Supplier = customergoods.Supplier,
                           ReservedWarehouseArea = customergoods.ReservedWarehouseArea,
                           Warehouse = customergoods.Warehouse,
                           OrderType = customergoods.OrderType,
                           Remarks = customergoods.Remarks,
                           AttachmentPath = customergoods.AttachmentPath,
                           CreatorId = customergoods.CreatorId,
                           CreationTime = customergoods.CreationTime,
                           LastModifierId = customergoods.LastModifierId,
                           LastModificationTime = customergoods.LastModificationTime,
                           CreatorName = user != null ? user.UserName : string.Empty
                       };

            var totalCount = await AsyncExecuter.CountAsync(query);

            var items = await AsyncExecuter.ToListAsync(
                query.OrderBy(input.Sorting ?? nameof(CustomergoodsModel.Id)).PageBy(input)
            );

            return new PagedResultDto<CustomergoodsDto>(totalCount, items);
        }
    }
} 